using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.PageFlow;
using WCSFContrib.PageFlow.Xml.Configuration;
using Microsoft.Practices.PageFlow.Utils;
using System.Reflection;
using WCSFContrib.PageFlow.Xml.Properties;
using System.Globalization;

namespace WCSFContrib.PageFlow.Xml
{
    public class XmlPageFlowDefinition : IPageFlowDefinition
    {
        NavigationGraph navigationGraph;
        Page abortPage;

        public XmlPageFlowDefinition(NavigationGraph navigationGraph)
        {
            Guard.ArgumentNotNull(navigationGraph, "navigationGraph");

            this.navigationGraph = navigationGraph;
            abortPage = new Page("PageFlow.AbortPage", navigationGraph.AbortUrl);
        }

        public AbandonBehavior Abandonable
        {
            get { return navigationGraph.Abandonable; }
        }

        public Page AbortPage
        {
            get { return abortPage; }
        }

        public bool Constrained
        {
            get { return !navigationGraph.Constrained; }
        }

        public string Name
        {
            get { return navigationGraph.Name; }
        }

        public string NotRunningRedirect
        {
            get { return navigationGraph.NotRunningUrl; }
        }

        public System.Collections.ObjectModel.ReadOnlyCollection<Page> Pages
        {
            get
            {
                List<Page> pages = new List<Page>();

                foreach (View view in navigationGraph.Views)
                {
                    pages.Add(GetPage(view.Name));
                }

                return pages.AsReadOnly();
            }
        }

        public Page StartPage
        {
            get { return GetPage(navigationGraph.StartView.Name); }
        }

        public Type PageFlowType
        {
            get { return navigationGraph.PageFlowType; }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
        public bool ContainsPage(Page page)
        {
            Guard.ArgumentNotNull(page, "page");

            View view = navigationGraph.TryGetViewFromName(page.Name);

            return (view != null && view.Url == page.Url);
        }

        public bool ContainsUrl(string url)
        {
            //Guard.ArgumentNotNullOrEmptyString(url, "url");
            View pageWithUrl = GetViewConfigurationElementFromUrl(url);

            if (pageWithUrl == null)
                return false;

            return navigationGraph.ContainsView(pageWithUrl.Name);
        }

        private View GetViewConfigurationElementFromUrl(string url)
        {
            return navigationGraph.TryGetViewFromUrl(url);
        }

        public Page GetPage(string stateName)
        {
            Guard.ArgumentNotNullOrEmptyString(stateName, "stateName");

            View view = navigationGraph.TryGetViewFromName(stateName);

            if (view != null)
            {
                List<string> transitions = new List<string>();

                foreach (Transition transition in view.Transitions)
                {
                    transitions.Add(transition.Name);
                }

                string defaultTransition = (transitions.Count > 0 ? transitions[0] : null);

                return new Page(view.Name, view.Url, defaultTransition, transitions);
            }
            
            throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Resources.StateDoesNotExists, stateName));                
        }

        public Page GetPageFromUrl(string url)
        {
            Guard.ArgumentNotNullOrEmptyString(url, "url");

            if (!ContainsUrl(url))
                throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Resources.UrlDoesNotExists, url));

            return GetPage(GetViewConfigurationElementFromUrl(url).Name);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
        public Page GetPageForTransition(Page currentPage, string transitionName, PageFlowState userDataStore)
        {
            Guard.ArgumentNotNull(currentPage, "currentPage");
            Guard.ArgumentNotNullOrEmptyString(transitionName, "transitionName");

            View view = navigationGraph.TryGetViewFromName(currentPage.Name);

            Transition transition = view.TryGetTransitionFromTransitionName(transitionName);

            string viewName;

            if (transition.Condition != null)
            {
                if (!typeof(IXmlPageFlowConditionEvaluator).IsAssignableFrom(navigationGraph.PageFlowType))
                    throw new System.Reflection.TargetException(String.Format(CultureInfo.CurrentCulture, "The Type '{0}' used for evaluating a condition does not inherits from '{1}'", navigationGraph.PageFlowType.FullName, typeof(IXmlPageFlowConditionEvaluator).FullName));

                IXmlPageFlowConditionEvaluator evaluator = (IXmlPageFlowConditionEvaluator)Activator.CreateInstance(navigationGraph.PageFlowType);
                ConditionalEventArgs conditionalEventArgs = new ConditionalEventArgs(userDataStore, transition.Condition);
                evaluator.OnEvaluateCondition(conditionalEventArgs);
                viewName = conditionalEventArgs.ViewName;
            }
            else
            {
                viewName = transition.View.Name;
            }

            return GetPage(viewName);
        }

        public IXmlPageFlowInstanceStore XmlPageFlowInstanceStore
        {
            get { return navigationGraph.InstanceStore; }
        }
    }
}
